Verilog-A 模拟事件
模拟事件 = 模拟域的「事件驱动」。仿真器是连续时间计算,事件语句让内部代码只在特定信号行为发生时执行,简化书写、减少计算量。
事件语句只能放在 analog begin...end 内(absdelta 例外,见下)。
事件触发通用语法
@(eventA or eventB or ...) begin
// 任一事件发生时执行
end
or不是计算符,表示多事件任一个触发。- 例:
@(cross(V(clk)-thresh, 1) or initial_step) begin ... end
事件一览
| 事件 | 含义 | 触发时机 |
|---|---|---|
initial_step |
仿真开始 | DC/AC/tran/noise 仿真开始阶段 |
final_step |
仿真结束 | 仿真正常结束(手动中断不触发) |
cross(expr[,dir[,t_tol[,e_tol]]]) |
信号穿越 0 值 | 仅动态仿真(tran 等) |
above(expr[,t_tol[,e_tol]]) |
信号 > 0 | 静态也触发(DC/initial_step) |
timer(start[,period[,t_tol]]) |
周期性事件 | 按仿真时间 |
absdelta(expr,delta[,t_tol[,e_tol]]) |
变化超过 delta | 0 时刻/稳定态/变化超 delta(仅 always 块) |
initial_step / final_step
@(initial_step) begin
// 初始化工作、输出设置信息(整个模块第一个被计算)
end
@(final_step) begin
// 仿真结束收尾
end
- 只支持 ac/dc/tran/noise 仿真(RF 等不触发)。
- 手动结束仿真(如 100uS 的 tran 在 90uS 手动停)不会触发 final_step。
cross(穿越检测)
@(cross(expr1 [, direction [, time_tol [, expr_tol]]])) begin ... end
- 检测信号穿越 0 值(正→负 或 负→正)。
direction:1=正向穿越(负→正),-1=负向穿越,0=双向(默认)。time_tol:持续时间小于该值的毛刺被忽略;expr_tol:数值下限。- DC 等静态仿真不触发(动态事件)。
@(cross(V(in)-vth, 1)) begin
out = 1; // 输入超过 vth 时置 1
end
above(大于检测)
@(above(expr1 [, time_tol [, expr_tol]])) begin ... end
- 信号值大于 0 时执行。
- 与 cross 区别:静态检测——DC、initial_step 等静态仿真也会触发。
@(above(V(in)-vth)) begin
out = 1;
end
timer(定时器)
@(timer(start_time [, period [, timetol]])) begin ... end
- 周期性事件,最常用于产生时钟信号。
timetol:事件触发的时间误差容限(如每 10uS 触发、容差 1nS)。
@(timer(0, 10u)) begin
clk = !clk; // 生成 10uS 周期时钟
end
V(out) <+ clk*V(vcc, gnd);
absdelta(增量检测)
@(absdelta(expr1, delta [, time_tol [, expr_tol]])) begin ... end
- 信号相比上次触发时变化超过 delta 即触发。
- 触发条件:0 时刻 / 计算得到初始稳定状态 / 变化量超过 delta。
- 只能用于
always语句(事件驱动域,不能放 analog 块)——仅 Verilog-AMS。 - 注意:设置不当会产生大量计算(信号经其他路径反馈影响被检测信号时可能振荡);设合理的 time_tol/expr_tol 可避免。
always @(absdelta(V(in), vth)) begin
out = out + 1; // 输入每变化 vth 就加 1
end
last_crossing(上次穿越时间)
last_crossing(signal, direction)
- 返回信号上次过 0 的时间点。
- direction:
0=任意方向,1=上升,-1=下降。 - ⚠️ 不是系统函数(无
$),其他仿真器不一定支持(Cadence 支持)。
ADC 综合示例(事件 + genvar + transition)
`include "constants.vams"
`include "disciplines.vams"
module adc(out, in, clk);
parameter real fullscale = 1.0;
parameter real td = 0, tt = 0;
parameter real vdd = 5.0;
parameter real thresh = vdd/2;
input in, clk;
output [0:7] out;
voltage in, clk;
voltage [0:7] out;
real sample, midpoint;
integer result[0:7];
integer i;
genvar j;
analog begin
@(cross(V(clk)-thresh, 1) or initial_step) begin
sample = V(in);
midpoint = fullscale/2.0;
for (i = 7; i >= 0; i = i - 1) begin
if (sample > midpoint) begin
result[i] = 1;
sample = sample - midpoint;
end else begin
result[i] = 0;
end
sample = 2.0*sample;
end
end
for(j=0;j<8;j=j+1)
V(out[j]) <+ transition(result[j] ? vdd : 0.0, td, tt);
end
endmodule
结构思路:先在事件内根据输入算出数值结果(数组),再用 genvar 循环赋给输出——减少模拟量互相影响与迭代。
相关笔记
- 模拟算子 → 07 - VerilogA 模拟算子
- 混合信号中的事件 → 12 - VerilogA 混合信号仿真
- 调试技巧(事件用于调试输出)→ 14 - VerilogA 调试与收敛